package app

import (
	"fmt"
	config "gitee.com/zhucheer/cfg"
	"gitee.com/zhucheer/orange/cfg"
	"gitee.com/zhucheer/orange/internal"
	"gitee.com/zhucheer/orange/utils"
	"github.com/nacos-group/nacos-sdk-go/clients"
	"github.com/nacos-group/nacos-sdk-go/clients/config_client"
	"github.com/nacos-group/nacos-sdk-go/common/constant"
	"github.com/nacos-group/nacos-sdk-go/vo"
	"path"
	"path/filepath"
	"strconv"
	"strings"
)

// nacos配置中心，注册中心支持
const DefaultTempDir = "/tmp"

var (
	nacosClientConfig *constant.ClientConfig
	nacosSrvConfig    []constant.ServerConfig
	nacosSrvStart     bool
)

func NewNacosSrv() {
	nacosEndpoints := cfg.Config.GetSliceString("nacos.endpoints")
	namespaceId := cfg.Config.GetString("nacos.namespace")
	tempDir := cfg.Config.GetString("nacos.tempDir")
	userName := cfg.Config.GetString("nacos.username")
	password := cfg.Config.GetString("nacos.password")
	if len(nacosEndpoints) == 0 {
		return
	}

	// 启动nacos替换配置
	if tempDir == "" {
		tempDir = DefaultTempDir
	}
	internal.ConsoleLog("Nacos Service Start")

	tempDir = strings.TrimRight(tempDir, "/")
	nacosClientConfig = constant.NewClientConfig(
		constant.WithNotLoadCacheAtStart(true),
		constant.WithLogDir(tempDir+"/nacos_log"),
		constant.WithCacheDir(tempDir+"/nacos_cache"),
		constant.WithTimeoutMs(5000),
		constant.WithLogLevel("info"),
	)
	if namespaceId != "" {
		nacosClientConfig.NamespaceId = namespaceId
	}
	if userName != "" && password != "" {
		nacosClientConfig.Username = userName
		nacosClientConfig.Password = password
	}

	for _, item := range nacosEndpoints {
		endpoint := strings.Split(item, ":")
		if len(endpoint) < 2 {
			panic("Nacos endpoints format ip:port error " + item)
		}
		port, _ := strconv.Atoi(endpoint[1])
		if port <= 0 {
			panic("Nacos endpoints format ip:port error " + item)
		}
		nacosSrvConfig = append(nacosSrvConfig, constant.ServerConfig{
			IpAddr:      endpoint[0],
			ContextPath: "/nacos",
			Port:        uint64(port),
			Scheme:      "http",
		})
	}
	nacosSrvStart = true

	useNacosConfig := cfg.Config.GetBool("nacos.config")
	useNacosDiscovery := cfg.Config.GetBool("nacos.discovery")
	if useNacosConfig {
		loadNacosConfig()
	}
	if useNacosDiscovery {
		discoveryReg()
	}
}

// discoveryReg 服务发现注册
func discoveryReg() {
	appName := cfg.Config.GetString("app.name")
	port := cfg.Config.GetInt("app.httpPort")
	groupName := cfg.GetString("app.groupName", "orange")
	ip := utils.GetLocalIp()
	if nacosSrvStart == false {
		return
	}
	namingClient, err := clients.NewNamingClient(
		vo.NacosClientParam{
			ClientConfig:  nacosClientConfig,
			ServerConfigs: nacosSrvConfig,
		},
	)
	if err != nil {
		panic("Nacos discovery client error:" + err.Error())
	}
	_, err = namingClient.RegisterInstance(vo.RegisterInstanceParam{
		Ip:          ip,
		Port:        uint64(port),
		ServiceName: appName,
		Weight:      10,
		Enable:      true,
		Healthy:     true,
		Ephemeral:   true,
		Metadata:    map[string]string{},
		ClusterName: "",
		GroupName:   groupName,
	})
	if err != nil {
		internal.ConsoleColorMsg("Nacos discovery regist error:"+err.Error(), 31)
		return
	}
	internal.ConsoleLog(fmt.Sprintf("Nacos discovery regist success %s:%d %s(%s)", ip, port, groupName, appName))

	// 退出后注销
	AppDefer(func() {
		internal.ConsoleColorMsg("Nacos discovery deregist", 31)
		namingClient.DeregisterInstance(vo.DeregisterInstanceParam{
			Ip:          ip,
			Port:        uint64(port),
			ServiceName: appName,
			Ephemeral:   true,
			GroupName:   groupName,
		})
	})
}

// loadNacosConfig 加载Nacos配置
// groupId使用应用名 dataId使用配置文件名 prod.yaml,test.yaml
func loadNacosConfig() {

	if nacosSrvStart == false {
		return
	}
	defaultGroupId := cfg.Config.GetString("app.name")
	groupId := cfg.GetString("nacos.groupId", defaultGroupId)
	configFilePath := cfg.GetStringFlag("config")
	defaultDataId := path.Base(filepath.ToSlash(configFilePath))
	dataId := cfg.GetString("nacos.dataId", defaultDataId)

	if groupId == "" || dataId == "" {
		panic("Nacos config groupId/dataId error")
	}

	// 创建配置中心客户端
	configClient, err := clients.NewConfigClient(
		vo.NacosClientParam{
			ClientConfig:  nacosClientConfig,
			ServerConfigs: nacosSrvConfig,
		},
	)

	if err != nil {
		panic("Nacos config client error:" + err.Error())
	}

	internal.ConsoleLog(fmt.Sprintf("Nacos ConfigCenter Loading groupId:%s, dataId:%s", groupId, dataId))
	cfg.Config = config.NewNacos(&config.NacosBase{
		ConfigClient: configClient,
		GroupId:      groupId,
		DataId:       dataId,
	})
	internal.ConsoleLog(fmt.Sprintf("Nacos ConfigCenter Loaded Success groupId:%s, dataId:%s", groupId, dataId))

	// 监听动态更新
	go listenConfigChange(configClient, dataId, groupId)
}

// listenConfigChange 监听配置
func listenConfigChange(configClient config_client.IConfigClient, dataId, groupId string) {
	// 退出后停止监听
	AppDefer(func() {
		internal.ConsoleColorMsg("cancle listen Nacos config change...", 31)
		configClient.CancelListenConfig(vo.ConfigParam{
			DataId: dataId,
			Group:  groupId,
		})
	})
	err := configClient.ListenConfig(vo.ConfigParam{
		DataId: dataId,
		Group:  groupId,
		OnChange: func(namespace, group, dataId, data string) {
			// 更新配置
			switch cfg.Config.ConfType {
			case "toml":
				handler, err := config.ReloadTomlData(data)
				if err != nil {
					internal.ConsoleColorMsg("Nacos ConfigCenter change failed "+err.Error(), 31)
					return
				}
				cfg.Config = handler
			case "yml", "yaml":
				handler, err := config.ReloadYamlData(data)
				if err != nil {
					internal.ConsoleColorMsg("Nacos ConfigCenter change failed "+err.Error(), 31)
					return
				}
				cfg.Config = handler
			}

			internal.ConsoleColorMsg("Nacos ConfigCenter change success", 32)
		},
	})
	if err != nil {
		internal.ConsoleColorMsg("Nacos ConfigCenter Listen error:"+err.Error(), 31)
	}
}
